package com.example.zluserservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.example.zluserservice.client.RoleFeignClient;
import com.example.zluserservice.common.annotation.OperationLog;
import com.example.zluserservice.common.annotation.RedisLock;
import com.example.zluserservice.common.constant.UserCacheConstant;
import com.example.zluserservice.common.exception.BaseException;
import com.example.zluserservice.common.exception.ProjectException;
import com.example.zluserservice.common.util.UserThreadLocal;
import com.example.zluserservice.dto.request.RegisterReqDTO;
import com.example.zluserservice.dto.request.UserReqDTO;
import com.example.zluserservice.dto.response.RegisterResDTO;
import com.example.zluserservice.dto.response.UserResDTO;
import com.example.zluserservice.entity.User;
import com.example.zluserservice.framework.mq.message.OperationLogMessage;
import com.example.zluserservice.framework.mq.producer.OperationLogProducer;
import com.example.zluserservice.framework.properties.SecurityConfigProperties;
import com.example.zluserservice.mapper.IUserMapper;
import com.example.zluserservice.service.IUserService;
import com.example.zluserservice.service.RegisterService;
import io.seata.spring.annotation.GlobalTransactional;
import org.aspectj.weaver.ast.Var;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Author zhenliu（孙凌岳）
 * @Description TODO
 * @Date 2025/6/18 19:40
 * @Version 1.0
 */
@Service
public class RegisterServiceImpl implements RegisterService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Resource
    private IUserMapper userMapper;

    @Resource
    private RoleFeignClient roleFeignClient;

    @Resource
    private IUserService userService;

    @Override
    @GlobalTransactional //分布式事务
    @OperationLog(action = "register_user",detail = "注册用户")
    @RedisLock(
            key = "'lock:user:register:' + #registerReqDTO.username",
            waitTime = 1, // 等待1秒
            leaseTime = 30, // 锁持有10秒
            unit = TimeUnit.SECONDS,
            block = true, // 阻塞等待
            errorMsg = "用户注册中，请稍后重试"
    )
    public RegisterResDTO register(RegisterReqDTO registerReqDTO) {
        String username = registerReqDTO.getUsername();

        //检查用户名唯一性
        if (checkUsernameExists(username)) {
            throw new BaseException("用户名已被占用");
        }

        //生成基于redis的自增ID
        Long userId = generatorUserId();

        //构造User实体
        User user = new User();
        user.setId(userId);
        user.setEmail(registerReqDTO.getEmail());
        user.setUsername(registerReqDTO.getUsername());
        user.setNickName(registerReqDTO.getNickName());
        user.setMobile(registerReqDTO.getMobile());
        user.setRemark("新注册的用户");
        user.setCreateBy(userId);
        user.setUpdateBy(userId);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setPassword(bCryptPasswordEncoder.encode(registerReqDTO.getPassword()));

        int flag = userMapper.insert(user);
        if (flag == 0) {
            throw new RuntimeException("注册失败：插入数据库失败");
        }

        roleFeignClient.bindDefaultRole(userId);

        RegisterResDTO registerResDTO = new RegisterResDTO();
        registerResDTO.setUserId(userId);
        registerResDTO.setUsername(user.getUsername());

        //将User信息转成JSON字符串
        String userJson = JSONUtil.toJsonStr(UserResDTO.builder()
                .id(user.getId())
                .username(user.getUsername())
                .email(user.getEmail())
                .nickName(user.getNickName())
                .mobile(user.getMobile())
                .email(user.getEmail())
                .createBy(user.getCreateBy())
                .updateBy(user.getUpdateBy())
                .createTime(user.getCreateTime())
                .updateTime(user.getUpdateTime())
                .build());

        //刷新ThreadLocal
        UserThreadLocal.setSubject(userJson);

            /**
             * 测试分布式事务
             */
            int i = 1/0;

        return registerResDTO;
    }

    /**
     * 校验账号全局唯一性
     * @param username
     * @return
     */
    private boolean checkUsernameExists(String username) {
        User user = userService.lambdaQuery()
                .eq(User::getUsername, username)
                .one();

        return user != null;
    }

    /**
     * 通过Redis自增序列得到序号
     * @return
     */
    private Long generatorUserId() {
        //通过Redis自增序列得到序号
        Long id = stringRedisTemplate.opsForValue().increment(UserCacheConstant.USERS_SHARD_KEY_ID_GENERATOR, 1);
        Long orderId = 1000000L + id;
        //1000016
        return orderId;
    }
}
